home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / OutOfPhase1.01Source / OutOfPhase Folder / DeterminedNoteStructure.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-01  |  15.1 KB  |  451 lines  |  [TEXT/KAHL]

  1. /* DeterminedNoteStructure.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #define ShowMeFrozenNoteRec
  31. #define ShowMe_NoteObjectRec
  32. #define ShowMeIncrParamUpdateRec
  33. #include "DeterminedNoteStructure.h"
  34. #include "Memory.h"
  35. #include "BinaryCodedDecimal.h"
  36. #include "NoteObject.h"
  37. #include "IncrementalParameterUpdator.h"
  38. #include "FloatingPoint.h"
  39. #include "Frequency.h"
  40. #include "PlayTrackInfoThang.h"
  41.  
  42.  
  43. static FrozenNoteRec*                FrozenNoteFreeList = NIL;
  44.  
  45.  
  46. /* flush cached frozen note blocks */
  47. void                                FlushFrozenNoteStructures(void)
  48.     {
  49.         while (FrozenNoteFreeList != NIL)
  50.             {
  51.                 FrozenNoteRec*        Temp;
  52.  
  53.                 Temp = FrozenNoteFreeList;
  54.                 FrozenNoteFreeList = FrozenNoteFreeList->Next;
  55.                 ReleasePtr((char*)Temp);
  56.             }
  57.     }
  58.  
  59.  
  60. /* make sure the frozen note structure is valid */
  61. #if DEBUG
  62. void                                ValidateFrozenNote(FrozenNoteRec* FrozenNote)
  63.     {
  64.         FrozenNoteRec*        Scan;
  65.  
  66.         CheckPtrExistence(FrozenNote);
  67.         Scan = FrozenNoteFreeList;
  68.         while (Scan != NIL)
  69.             {
  70.                 if (Scan == FrozenNote)
  71.                     {
  72.                         PRERR(ForceAbort,"ValidateFrozenNote:  note record is on free list");
  73.                     }
  74.                 Scan = Scan->Next;
  75.             }
  76.     }
  77. #endif
  78.  
  79.  
  80. /* dispose of a note object */
  81. void                                DisposeFrozenNote(FrozenNoteRec* FrozenNote)
  82.     {
  83.         ValidateFrozenNote(FrozenNote);
  84.         FrozenNote->Next = FrozenNoteFreeList;
  85.         FrozenNoteFreeList = FrozenNote;
  86.     }
  87.  
  88.  
  89. /* build a new note object with all parameters determined.  *StartAdjustOut */
  90. /* indicates how many ticks before (negative) or after (positive) now that */
  91. /* the key-down should occur.  this is added to the scanning gap size and envelope */
  92. /* origins to figure out how to schedule the note */
  93. FrozenNoteRec*            FixNoteParameters(struct IncrParamUpdateRec* GlobalParamSource,
  94.                                             struct NoteObjectRec* Note, long* StartAdjustOut,
  95.                                             float OverallVolumeScaling, float EnvelopeTicksPerDurationTick)
  96.     {
  97.         FrozenNoteRec*        FrozenNote;
  98.         float                            FloatTemp;
  99.         float                            FloatOtherTemp;
  100.         long                            IntTemp;
  101.  
  102.         CheckPtrExistence(GlobalParamSource);
  103.         CheckPtrExistence(Note);
  104.         ERROR(IsItACommand(Note),PRERR(ForceAbort,"FixNoteParameters:  note is a command"));
  105.         ERROR(GetNoteIsItARest(Note),PRERR(ForceAbort,"FixNoteParameters:  can't handle rests"));
  106.  
  107.         if (FrozenNoteFreeList != NIL)
  108.             {
  109.                 FrozenNote = FrozenNoteFreeList;
  110.                 FrozenNoteFreeList = FrozenNoteFreeList->Next;
  111.             }
  112.          else
  113.             {
  114.                 FrozenNote = (FrozenNoteRec*)AllocPtrCanFail(sizeof(FrozenNoteRec),"FrozenNoteRec");
  115.                 if (FrozenNote == NIL)
  116.                     {
  117.                         return NIL;
  118.                     }
  119.             }
  120.         EXECUTE(FrozenNote->Next = (FrozenNoteRec*)0x81818181;)
  121.  
  122.         /* reference to the note that defines this note. */
  123.         FrozenNote->OriginalNote = Note;
  124.  
  125.         /* frequency determined by pitch index + detuning, in Hertz */
  126.         IntTemp = Note->a.Note.Pitch + GlobalParamSource->TransposeHalfsteps;
  127.         if (IntTemp < 0)
  128.             {
  129.                 IntTemp = 0;
  130.             }
  131.         else if (IntTemp > NUMNOTES - 1)
  132.             {
  133.                 IntTemp = NUMNOTES - 1;
  134.             }
  135.         FloatTemp = (float)FEXP(((float)(IntTemp - CENTERNOTE) / 12) * (float)LOG2)
  136.             * (float)MIDDLEC;
  137.         switch (Note->Flags & eDetuningModeMask)
  138.             {
  139.                 default:
  140.                     EXECUTE(PRERR(ForceAbort,"FixNoteParameters:  bad detuning mode"));
  141.                     break;
  142.                 case eDetuningModeDefault:
  143.                     FloatOtherTemp = SmallBCD2Single(Note->a.Note.Detuning)
  144.                         * LargeBCD2Single(GlobalParamSource->CurrentDetune);
  145.                     if (GlobalParamSource->DetuneHertz)
  146.                         {
  147.                             goto DetuneHertzPoint;
  148.                         }
  149.                      else
  150.                         {
  151.                             goto DetuneHalfStepsPoint;
  152.                         }
  153.                     break;
  154.                 case eDetuningModeHalfSteps:
  155.                     FloatOtherTemp = SmallBCD2Single(Note->a.Note.Detuning)
  156.                         + LargeBCD2Single(GlobalParamSource->CurrentDetune);
  157.                  DetuneHalfStepsPoint:
  158.                     FrozenNote->NominalFrequency = FloatTemp
  159.                         * (float)FEXP((FloatOtherTemp / 12) * (float)LOG2);
  160.                     break;
  161.                 case eDetuningModeHertz:
  162.                     FloatOtherTemp = SmallBCD2Single(Note->a.Note.Detuning)
  163.                         + LargeBCD2Single(GlobalParamSource->CurrentDetune);
  164.                  DetuneHertzPoint:
  165.                     FrozenNote->NominalFrequency = FloatTemp + FloatOtherTemp;
  166.                     break;
  167.             }
  168.  
  169.         /* frequency used for doing multisampling, in Hertz */
  170.         if (Note->a.Note.MultisamplePitchAsIf != -1)
  171.             {
  172.                 FrozenNote->MultisampleFrequency = (float)FEXP(((float)(Note->a.Note
  173.                     .MultisamplePitchAsIf - CENTERNOTE) / 12) * (float)LOG2) * (float)MIDDLEC;
  174.             }
  175.          else
  176.             {
  177.                 FrozenNote->MultisampleFrequency = FrozenNote->NominalFrequency;
  178.             }
  179.  
  180.         /* acceleration of envelopes */
  181.         FrozenNote->HurryUpFactor = SmallBCD2Single(Note->a.Note.HurryUpFactor)
  182.             * LargeBCD2Single(GlobalParamSource->CurrentHurryUp);
  183.  
  184.         /* duration, in envelope ticks */
  185.         switch (Note->Flags & eDurationMask)
  186.             {
  187.                 default:
  188.                     EXECUTE(PRERR(ForceAbort,"FixNoteParameters:  bad duration flags"));
  189.                     break;
  190.                 case e64thNote:
  191.                     IntTemp = DURATIONUPDATECLOCKRESOLUTION / 64;
  192.                     break;
  193.                 case e32ndNote:
  194.                     IntTemp = DURATIONUPDATECLOCKRESOLUTION / 32;
  195.                     break;
  196.                 case e16thNote:
  197.                     IntTemp = DURATIONUPDATECLOCKRESOLUTION / 16;
  198.                     break;
  199.                 case e8thNote:
  200.                     IntTemp = DURATIONUPDATECLOCKRESOLUTION / 8;
  201.                     break;
  202.                 case e4thNote:
  203.                     IntTemp = DURATIONUPDATECLOCKRESOLUTION / 4;
  204.                     break;
  205.                 case e2ndNote:
  206.                     IntTemp = DURATIONUPDATECLOCKRESOLUTION / 2;
  207.                     break;
  208.                 case eWholeNote:
  209.                     IntTemp = DURATIONUPDATECLOCKRESOLUTION;
  210.                     break;
  211.                 case eDoubleNote:
  212.                     IntTemp = DURATIONUPDATECLOCKRESOLUTION * 2;
  213.                     break;
  214.                 case eQuadNote:
  215.                     IntTemp = DURATIONUPDATECLOCKRESOLUTION * 4;
  216.                     break;
  217.             }
  218.         switch (Note->Flags & eDivisionMask)
  219.             {
  220.                 default:
  221.                     EXECUTE(PRERR(ForceAbort,"FixNoteParameters:  bad division flags"));
  222.                     break;
  223.                 case eDiv1Modifier:
  224.                     break;
  225.                 case eDiv3Modifier:
  226.                     IntTemp = IntTemp / 3;
  227.                     break;
  228.                 case eDiv5Modifier:
  229.                     IntTemp = IntTemp / 5;
  230.                     break;
  231.                 case eDiv7Modifier:
  232.                     IntTemp = IntTemp / 7;
  233.                     break;
  234.             }
  235.         if ((Note->Flags & eDotModifier) != 0)
  236.             {
  237.                 IntTemp = (IntTemp * 3) / 2;
  238.             }
  239.         FloatTemp = IntTemp;
  240.         switch (Note->Flags & eDurationAdjustMask)
  241.             {
  242.                 default:
  243.                     EXECUTE(PRERR(ForceAbort,"FixNoteParameters:  bad duration adjust flags"));
  244.                     break;
  245.                 case eDurationAdjustDefault:
  246.                     if (GlobalParamSource->DurationAdjustAdditive)
  247.                         {
  248.                             goto DurationAdjustAddPoint;
  249.                         }
  250.                      else
  251.                         {
  252.                             goto DurationAdjustMultPoint;
  253.                         }
  254.                     break;
  255.                 case eDurationAdjustAdditive:
  256.                  DurationAdjustAddPoint:
  257.                     FloatTemp = FloatTemp + SmallBCD2Single(Note->a.Note.DurationAdjust)
  258.                         * (DURATIONUPDATECLOCKRESOLUTION / 4);
  259.                     break;
  260.                 case eDurationAdjustMultiplicative:
  261.                  DurationAdjustMultPoint:
  262.                     FloatTemp = FloatTemp * SmallBCD2Single(Note->a.Note.DurationAdjust);
  263.                     break;
  264.             }
  265.         if (GlobalParamSource->DurationAdjustAdditive)
  266.             {
  267.                 FloatTemp = FloatTemp + LargeBCD2Single(GlobalParamSource->CurrentDurationAdjust)
  268.                     * (DURATIONUPDATECLOCKRESOLUTION / 4);
  269.             }
  270.          else
  271.             {
  272.                 FloatTemp = FloatTemp * LargeBCD2Single(GlobalParamSource->CurrentDurationAdjust);
  273.             }
  274.         /* this line is what converts from duration update ticks to envelope ticks */
  275.         FrozenNote->Duration = FloatTemp * EnvelopeTicksPerDurationTick;
  276.  
  277.         /* portamento duration, in envelope ticks */
  278.         FrozenNote->PortamentoDuration = SmallBCD2Single(Note->a.Note.PortamentoDuration)
  279.             * (DURATIONUPDATECLOCKRESOLUTION / 4) * EnvelopeTicksPerDurationTick;
  280.  
  281.         /* first release point, in envelope ticks after start of note */
  282.         switch (Note->Flags & eRelease1OriginMask)
  283.             {
  284.                 default:
  285.                     EXECUTE(PRERR(ForceAbort,"FixNoteParameters:  bad release point 1 origin flags"));
  286.                     break;
  287.                 case eRelease1FromStart:
  288.                     FrozenNote->ReleasePoint1 = SmallBCD2Single(Note->a.Note.ReleasePoint1)
  289.                         * FrozenNote->Duration;
  290.                     FrozenNote->Release1FromStart = True;
  291.                     break;
  292.                 case eRelease1FromEnd:
  293.                     FrozenNote->ReleasePoint1 = (1 - SmallBCD2Single(Note->a.Note.ReleasePoint1))
  294.                         * FrozenNote->Duration;
  295.                     FrozenNote->Release1FromStart = False;
  296.                     break;
  297.                 case eRelease1FromDefault:
  298.                     if (GlobalParamSource->ReleasePoint1FromStart)
  299.                         {
  300.                             FrozenNote->ReleasePoint1 = (SmallBCD2Single(Note->a.Note.ReleasePoint1)
  301.                                 + LargeBCD2Single(GlobalParamSource->CurrentReleasePoint1))
  302.                                 * FrozenNote->Duration;
  303.                             FrozenNote->Release1FromStart = True;
  304.                         }
  305.                      else
  306.                         {
  307.                             FrozenNote->ReleasePoint1 = (1 - (SmallBCD2Single(
  308.                                 Note->a.Note.ReleasePoint1) + LargeBCD2Single(
  309.                                 GlobalParamSource->CurrentReleasePoint1))) * FrozenNote->Duration;
  310.                             FrozenNote->Release1FromStart = False;
  311.                         }
  312.                     break;
  313.             }
  314.  
  315.         /* second release point, in envelope ticks after start of note */
  316.         switch (Note->Flags & eRelease2OriginMask)
  317.             {
  318.                 default:
  319.                     EXECUTE(PRERR(ForceAbort,"FixNoteParameters:  bad release point 2 origin flags"));
  320.                     break;
  321.                 case eRelease2FromStart:
  322.                     FrozenNote->ReleasePoint2 = SmallBCD2Single(Note->a.Note.ReleasePoint2)
  323.                         * FrozenNote->Duration;
  324.                     FrozenNote->Release2FromStart = True;
  325.                     break;
  326.                 case eRelease2FromEnd:
  327.                     FrozenNote->ReleasePoint2 = (1 - SmallBCD2Single(Note->a.Note.ReleasePoint2))
  328.                         * FrozenNote->Duration;
  329.                     FrozenNote->Release2FromStart = False;
  330.                     break;
  331.                 case eRelease2FromDefault:
  332.                     if (GlobalParamSource->ReleasePoint2FromStart)
  333.                         {
  334.                             FrozenNote->ReleasePoint2 = (SmallBCD2Single(Note->a.Note.ReleasePoint2)
  335.                                 + LargeBCD2Single(GlobalParamSource->CurrentReleasePoint2))
  336.                                 * FrozenNote->Duration;
  337.                             FrozenNote->Release2FromStart = True;
  338.                         }
  339.                      else
  340.                         {
  341.                             FrozenNote->ReleasePoint2 = (1 - (SmallBCD2Single(
  342.                                 Note->a.Note.ReleasePoint2) + LargeBCD2Single(
  343.                                 GlobalParamSource->CurrentReleasePoint2))) * FrozenNote->Duration;
  344.                             FrozenNote->Release2FromStart = False;
  345.                         }
  346.                     break;
  347.             }
  348.  
  349.         /* third release point, in envelope ticks after start of note */
  350.         if ((Note->Flags & eRelease3FromStartNotEnd) != 0)
  351.             {
  352.                 FrozenNote->ReleasePoint3 = 0;
  353.                 FrozenNote->Release3FromStart = True;
  354.             }
  355.          else
  356.             {
  357.                 FrozenNote->ReleasePoint3 = FrozenNote->Duration;
  358.                 FrozenNote->Release3FromStart = False;
  359.             }
  360.  
  361.         /* overall loudness adjustment for envelopes, including global volume scaling */
  362.         FrozenNote->LoudnessAdjust = SmallBCD2Single(Note->a.Note.OverallLoudnessAdjustment)
  363.             * LargeBCD2Single(GlobalParamSource->CurrentVolume) * OverallVolumeScaling;
  364.  
  365.         /* stereo positioning for note */
  366.         FloatTemp = SmallBCD2Single(Note->a.Note.StereoPositionAdjustment)
  367.             + LargeBCD2Single(GlobalParamSource->CurrentStereoPosition);
  368.         if (FloatTemp < -1)
  369.             {
  370.                 FloatTemp = -1;
  371.             }
  372.         else if (FloatTemp > 1)
  373.             {
  374.                 FloatTemp = 1;
  375.             }
  376.         FrozenNote->StereoPosition = FloatTemp;
  377.  
  378.         /* accent values for controlling envelopes */
  379.         FrozenNote->Accent1 = SmallBCD2Single(Note->a.Note.Accent1)
  380.             + LargeBCD2Single(GlobalParamSource->CurrentAccent1);
  381.         FrozenNote->Accent2 = SmallBCD2Single(Note->a.Note.Accent2)
  382.             + LargeBCD2Single(GlobalParamSource->CurrentAccent2);
  383.         FrozenNote->Accent3 = SmallBCD2Single(Note->a.Note.Accent3)
  384.             + LargeBCD2Single(GlobalParamSource->CurrentAccent3);
  385.         FrozenNote->Accent4 = SmallBCD2Single(Note->a.Note.Accent4)
  386.             + LargeBCD2Single(GlobalParamSource->CurrentAccent4);
  387.  
  388.         /* pitch displacement maximum depth, in tonal Hertz */
  389.         FloatTemp = SmallBCD2Single(Note->a.Note.PitchDisplacementDepthAdjustment);
  390.         switch (Note->Flags & ePitchDisplacementDepthModeMask)
  391.             {
  392.                 default:
  393.                     EXECUTE(PRERR(ForceAbort,"FixNoteParameters:  bad pitch disp depth flags"));
  394.                     break;
  395.                 case ePitchDisplacementDepthModeHalfSteps:
  396.                     FrozenNote->PitchDisplacementDepthInHertz = False;
  397.                     break;
  398.                 case ePitchDisplacementDepthModeHertz:
  399.                     FrozenNote->PitchDisplacementDepthInHertz = True;
  400.                     break;
  401.                 case ePitchDisplacementDepthModeDefault:
  402.                     FloatTemp = FloatTemp * LargeBCD2Single(
  403.                         GlobalParamSource->CurrentPitchDisplacementDepthLimit);
  404.                     FrozenNote->PitchDisplacementDepthInHertz
  405.                         = GlobalParamSource->PitchDisplacementDepthHertz;
  406.                     break;
  407.             }
  408.         FrozenNote->PitchDisplacementDepthLimit = FloatTemp;
  409.  
  410.         /* pitch displacement maximum rate, in LFO Hertz */
  411.         FrozenNote->PitchDisplacementRateLimit = SmallBCD2Double(
  412.             Note->a.Note.PitchDisplacementRateAdjustment)
  413.             * LargeBCD2Double(GlobalParamSource->CurrentPitchDisplacementRateLimit);
  414.  
  415.         /* pitch displacement start point, in envelope clocks after start of note */
  416.         switch (Note->Flags & ePitchDisplacementStartOriginMask)
  417.             {
  418.                 default:
  419.                     EXECUTE(PRERR(ForceAbort,"FixNoteParameters:  bad pitch disp start flags"));
  420.                     break;
  421.                 case ePitchDisplacementStartFromStart:
  422.                     FrozenNote->PitchDisplacementStartPoint = FrozenNote->Duration
  423.                         * SmallBCD2Single(Note->a.Note.PitchDisplacementStartPoint);
  424.                     break;
  425.                 case ePitchDisplacementStartFromEnd:
  426.                     FrozenNote->PitchDisplacementStartPoint = FrozenNote->Duration
  427.                         * (1 - SmallBCD2Single(Note->a.Note.PitchDisplacementStartPoint));
  428.                     break;
  429.                 case ePitchDisplacementStartFromDefault:
  430.                     if (GlobalParamSource->PitchDisplacementStartPointFromStart)
  431.                         {
  432.                             FrozenNote->PitchDisplacementStartPoint = FrozenNote->Duration
  433.                                 * (SmallBCD2Single(Note->a.Note.PitchDisplacementStartPoint)
  434.                                 + LargeBCD2Single(GlobalParamSource->CurrentPitchDisplacementStartPoint));
  435.                         }
  436.                      else
  437.                         {
  438.                             FrozenNote->PitchDisplacementStartPoint = FrozenNote->Duration
  439.                                 * (1 - (SmallBCD2Single(Note->a.Note.PitchDisplacementStartPoint)
  440.                                 + LargeBCD2Single(GlobalParamSource->CurrentPitchDisplacementStartPoint)));
  441.                         }
  442.                     break;
  443.             }
  444.  
  445.         *StartAdjustOut = (SmallBCD2Single(Note->a.Note.EarlyLateAdjust)
  446.             + LargeBCD2Single(GlobalParamSource->CurrentEarlyLateAdjust))
  447.             * FrozenNote->Duration;
  448.  
  449.         return FrozenNote;
  450.     }
  451.